---
title: Scripts et gestion d'évènements
description: >-
  Comment ajouter de l'interactivité côté client aux composants Astro en utilisant les 
  API JavaScript natives du navigateur.
i18nReady: true
---
import ReadMore from '~/components/ReadMore.astro'

Vous pouvez envoyer du JavaScript au navigateur et ajouter des fonctionnalités à vos composants Astro en utilisant les balises `<script>` dans le modèle de composant.

Les scripts ajoutent de l'interactivité à votre site, comme la gestion des événements ou la mise à jour du contenu de manière dynamique, sans avoir besoin d'un [framework d'interface utilisateur](/fr/guides/framework-components/) comme React, Svelte ou Vue. Cela évite les frais liés à l'envoi de JavaScript par le framework et ne nécessite aucune connaissance d'un framework supplémentaire pour créer un site web ou une application complète.

## Scripts côté client

Les scripts peuvent être utilisés pour ajouter des écouteurs d'événements, envoyer des données analytiques, lire des animations et tout ce que JavaScript permet de faire sur le web.

Astro améliore automatiquement la balise HTML standard `<script>` avec le regroupement, TypeScript et plus encore. Référez-vous à [comment Astro traite les scripts](#traitement-des-scripts) pour plus de détails.

```astro title="src/components/ConfettiButton.astro"
<button data-confetti-button>Célébrer !</button>

<script>
  // Importer depuis le paquet npm.
  import confetti from 'canvas-confetti';

  // Trouver le DOM de notre composant dans la page.
  const buttons = document.querySelectorAll('[data-confetti-button]');

  // Ajouter l'écouteur d'événement pour déclencher des confettis lorsqu'un bouton est cliqué.
  buttons.forEach((button) => {
    button.addEventListener('click', () => confetti());
  });
</script>
```

<ReadMore>Consultez [quand vos scripts ne seront pas traités](#scripts-non-traités) pour résoudre les problèmes de comportement des scripts ou pour savoir comment désactiver intentionnellement ce traitement.</ReadMore>


### Traitement des scripts

Par défaut, Astro traite les balises `<script>` qui ne contiennent aucun attribut (autre que `src`) de la manière suivante :

- **Prise en charge de TypeScript :** Tous les scripts utilisent TypeScript par défaut.
- **Regroupement des importations :** Importez des fichiers locaux ou des modules npm, qui seront regroupés.
- **Type Module :** Les scripts traités utilisent [`type="module"`](https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Modules) automatiquement.
- **Déduplication :** Si un composant contenant un `<script>` est utilisé plusieurs fois sur une page, le script ne sera inclus qu'une seule fois.
- **Incorporation automatique :** Si le script est suffisamment petit, Astro l'intégrera directement dans le HTML pour réduire le nombre de requêtes.
```astro title="src/components/Example.astro"
<script>
  // Optimisé ! Regroupé ! TypeScript !
  // L'importation de scripts locaux et de paquets npm fonctionne.
</script>
```

### Scripts non traités

Astro ne traitera pas une balise `<script>` si elle possède un attribut autre que `src`.

Vous pouvez ajouter la directive [`is:inline`](/fr/reference/directives-reference/#isinline) pour désactiver intentionnellement le traitement d'un script.

```astro title="src/components/InlineScript.astro" "is:inline"
<script is:inline>
  // Sera rendu dans le code HTML exactement comme il est écrit !
  // Non transformé : pas de TypeScript et pas de résolution d'importation par Astro.
  // S'il est utilisé à l'intérieur d'un composant, ce code est dupliqué pour chaque instance.
</script>
```

### Inclure des fichiers JavaScript dans la page

Vous pouvez vouloir écrire vos scripts comme des fichiers `.js`/`.ts` séparés ou avoir besoin de référencer un script externe sur un autre serveur. Vous pouvez le faire en les référençant dans l'attribut `src` d'une balise `<script>`.

#### Importer des scripts locaux

**Quand l'utiliser :** Si votre script se trouve dans `src/`.

Astro traitera ces scripts conformément aux [règles de traitement des scripts](#traitement-des-scripts).

```astro title="src/components/LocalScripts.astro"
<!-- chemin relatif du script dans `src/scripts/local.js` -->
<script src="../scripts/local.js"></script>

<!-- fonctionne également pour les fichiers TypeScript locaux -->
<script src="./script-with-types.ts"></script>
```

#### Charger des scripts externes

**Quand l'utiliser :** Si votre fichier JavaScript se trouve à l'intérieur du dossier `public/` ou sur un CDN.

Pour charger des scripts en dehors du dossier `src/` de votre projet, incluez la directive `is:inline`. Cette approche permet d'éviter le traitement JavaScript, le regroupement et l'optimisation du JavaScript qui sont fournis par Astro lorsque vous importez des scripts comme décrit ci-dessus.

```astro title="src/components/ExternalScripts.astro" "is:inline"
<!-- chemin absolu du script à `public/my-script.js` -->
<script is:inline src="/my-script.js"></script>

<!-- URL complète vers un script sur un serveur distant -->
<script is:inline src="https://my-analytics.com/script.js"></script>
```

## Modèles communs de script

### Gérer le `onclick` et d'autres évènements

Certains frameworks d'interface utilisateur utilisent une syntaxe personnalisée pour la gestion des événements comme `onClick={...}` (React/Preact) ou `@click="..."` (Vue). Astro suit au plus près le HTML standard et n’utilise pas de syntaxe personnalisée pour les évènements.

Au lieu de cela, vous pouvez utiliser [`addEventListener`](https://developer.mozilla.org/fr/docs/Web/API/EventTarget/addEventListener) dans une balise `<script>` pour gérer les interactions avec l'utilisateur.

```astro title="src/components/AlertButton.astro"
<button class="alert">Cliquez-moi !</button>

<script>
  // Trouver tous les boutons avec la classe `alert` sur la page.
  const buttons = document.querySelectorAll('button.alert');

  // Gérer les clics sur chaque bouton.
  buttons.forEach((button) => {
    button.addEventListener('click', () => {
      alert('Le bouton a été cliqué !');
    });
  });
</script>
```

Si vous avez plusieurs composants `<AlertButton />` sur une page, Astro n'exécutera pas le script plusieurs fois. Les scripts sont regroupés et ne sont inclus qu'une seule fois par page. L'utilisation de `querySelectorAll` garantit que ce script attache l'écouteur d'évènements à chaque bouton possédant la classe `alert` présent sur la page.


### Composants Web avec des éléments personnalisés

Vous pouvez créer vos propres éléments HTML avec un comportement personnalisé en utilisant la norme Web Components. La définition d'un [élément personnalisé](https://developer.mozilla.org/fr/docs/Web/API/Web_components/Using_custom_elements) dans un composant `.astro` vous permet de créer des composants interactifs sans avoir besoin d'une bibliothèque de framework UI.

Dans cet exemple, nous définissons un nouvel élément HTML `<astro-heart>` qui enregistre le nombre de fois que vous cliquez sur le bouton en forme de cœur et met à jour l'élément `<span>` avec le dernier décompte.

```astro title="src/components/AstroHeart.astro"
<!-- Enveloppez les éléments du composant dans notre élément personnalisé "astro-heart" -->
<astro-heart>
  <button aria-label="Heart">💜</button> × <span>0</span>
</astro-heart>

<script>
  // Définir le comportement de notre nouveau type d'élément HTML.
  class AstroHeart extends HTMLElement {
    connectedCallback() {
      let count = 0;

      const heartButton = this.querySelector('button');
      const countSpan = this.querySelector('span');

      // À chaque fois que le bouton est cliqué, on met à jour le compte.
			heartButton.addEventListener('click', () => {
        count++;
        countSpan.textContent = count;
      });
		}
  }

  // Dites au navigateur d'utiliser notre classe AstroHeart pour les éléments <astro-heart>.
  customElements.define('astro-heart', AstroHeart);
</script>
```

L'utilisation d'un élément personnalisé présente deux avantages :

1. Au lieu de chercher dans toute la page en utilisant `document.querySelector()`, vous pouvez utiliser `this.querySelector()`, qui ne recherche que dans l'instance courante de l'élément personnalisé. Cela permet de travailler plus facilement avec les enfants d'une seule instance de composant à la fois.

2. Bien qu'un `<script>` ne s'exécute qu'une seule fois, le navigateur exécutera la méthode `connectedCallback()` de notre élément personnalisé chaque fois qu'il trouvera `<astro-heart>` sur la page.  Cela signifie que vous pouvez écrire en toute sécurité du code pour un seul composant à la fois, même si vous avez l'intention d'utiliser ce composant plusieurs fois sur une page.

<ReadMore>Pour en savoir plus sur les éléments personnalisés, consultez [le guide des composants Web réutilisables de web.dev (Anglais)](https://web.dev/custom-elements-v1/) et [l'introduction aux éléments personnalisés de MDN](https://developer.mozilla.org/fr/docs/Web/API/Web_components/Using_custom_elements).</ReadMore>


### Transmettre les variables du frontmatter aux scripts

Dans les composants Astro, le code dans [le frontmatter](/fr/basics/astro-components/#le-script-du-composant) (entre les délimiteurs `---`) s'exécute sur le serveur et n'est pas disponible dans le navigateur.

Pour transmettre des variables côté serveur aux scripts côté client, définissez-les dans des [attributs `data-*`](https://developer.mozilla.org/fr/docs/Web/HTML/How_to/Use_data_attributes) sur les éléments HTML. Les scripts peuvent ensuite accéder à ces valeurs grâce à la propriété `dataset`.

Dans cet exemple de composant, une propriété `message` est stockée dans un attribut `data-message`, de sorte que l'élément personnalisé puisse lire `this.dataset.message` et obtenir la valeur de la propriété dans le navigateur.

```astro title="src/components/AstroGreet.astro" {2} /data-message={.+}/ "this.dataset.message"
---
const { message = 'Bienvenue, le monde !' } = Astro.props;
---

<!-- Stocker la propriété message comme attribut de données. -->
<astro-greet data-message={message}>
  <button>Saluer !</button>
</astro-greet>

<script>
  class AstroGreet extends HTMLElement {
    connectedCallback() {
      // Lisez le message de l’attribut data.
      const message = this.dataset.message;
      const button = this.querySelector('button');
      button.addEventListener('click', () => {
        alert(message);
      });
		}
  }

  customElements.define('astro-greet', AstroGreet);
</script>
```

Nous pouvons maintenant utiliser notre composant plusieurs fois et être accueillis par un message différent à chaque fois.

```astro title="src/pages/example.astro"
---
import AstroGreet from '../components/AstroGreet.astro';
---

<!-- Utilisez le message par défaut: "Bienvenue, le monde !" -->
<AstroGreet />

<!-- Utiliser des messages personnalisés passés comme props. -->
<AstroGreet message="Belle journée pour créer des composants !" />
<AstroGreet message="Content que tu sois là ! 👋" />
```

:::tip[Le saviez-vous ?]
C'est en fait ce qu'Astro fait dans les coulisses lorsque vous passez des props à un composant écrit avec un framework d'interface utilisateur comme React ! Pour les composants avec une directive `client:*`, Astro crée un élément personnalisé `<astro-island>` avec un attribut `props` qui stocke vos paramètres côté serveur dans la sortie HTML.
:::

### Combinaison de scripts et de frameworks UI

Les éléments rendus par un framework UI peuvent ne pas être disponibles au moment de l'exécution d'une balise `<script>`. Si votre script doit également gérer les [composants d'un framework UI](/fr/guides/framework-components/), il est recommandé d'utiliser un élément personnalisé.
